#include "xmlNodeTree.h"
#include "tinyxml/tinyxml.h"
#include <boost/algorithm/string.hpp>

namespace lpe{
	namespace resman{

		XMLNodeTree::~XMLNodeTree()
		{
			if(m_childNodeList.size() > 0)
			{
				std::vector<XMLNodeTree*>::iterator dd = m_childNodeList.begin();
				for(;dd != m_childNodeList.end(); ++dd)
				{
					delete (*dd);
				}
			}
		}
		XMLNodeTree::XMLNodeTree()
			:m_nodeName("")
			,m_nodeText("")
			,m_nAttributes(0)
		{}

		bool XMLNodeTree::readNode(TiXmlNode* node)
		{
			if(node->ToElement()->Value() != NULL)
			{
				m_nodeName = std::string(node->ToElement()->Value());
			}else
			{
				// En principio esta situacion es imposible pero protege al codigo cuando llamamos a getChildNodeByName.
				THROW_EXCEPTION(lpe::core::xmlParsingException, "El valor de un nodo no puede ser NULL!!");
			}
			if(node->ToElement()->GetText() != NULL)
			{
				m_nodeText = std::string(node->ToElement()->GetText());
			}
			const TiXmlAttribute* attrib = node->ToElement()->FirstAttribute();
			while(attrib != 0)
			{
				m_nodeAttributes[attrib->Name()] = attrib->Value();
				++m_nAttributes;
				attrib = attrib->Next();
			}
			// leyendo los hijos de este nodo
			//nota: TINYXML no procesa bien las etiquetas vacias como <aa></aa>, y node->FirstChild devuelve null. Ahora lo controlo
			// graciass al 'if'
			TiXmlNode* n = node->FirstChild();
			if(n == 0)
				return true;
			assert(n != NULL);
			if(n->Type() == TiXmlNode::TINYXML_ELEMENT)
			{
				while(n != 0)
				{
					XMLNodeTree* nodetree = new XMLNodeTree();
					nodetree->readNode(n);
					m_childNodeList.push_back(nodetree);
					n = n->NextSibling();
				}
			}
			return true;
		}
//#ifdef DEBUG
		void XMLNodeTree::printNodeTree(const std::string& prevTabs)
		{
			std::stringstream ss;
			ss << prevTabs << "Name: " << m_nodeName << " text: \"" << m_nodeText <<"\" ";
			std::map<std::string, std::string>::iterator it = m_nodeAttributes.begin();
			for(; it != m_nodeAttributes.end(); ++it)
			{
				ss << (*it).first << "=" << (*it).second << " ";
			}
			std::cout << ss.str() << "\n";
			std::vector<XMLNodeTree*>::iterator lt = m_childNodeList.begin();
			for(; lt != m_childNodeList.end(); ++lt)
			{
				(*lt)->printNodeTree(prevTabs + std::string("\t"));
			}
		}
//#endif
		XMLNodeTree* XMLNodeTree::getChildNodeByName(const std::string& name)
		{
			std::vector<XMLNodeTree*>::iterator it = m_childNodeList.begin();
			for(;it != m_childNodeList.end(); ++it)
			{
				if((*it)->getNodeName() == name)
					return (*it);
			}
			return NULL;
		}

		bool XMLNodeTree::getAttributeValueByName(const std::string& attribName, std::string& value)
		{
			std::map<std::string,std::string>::iterator it = m_nodeAttributes.find(attribName);
			if(it != m_nodeAttributes.end())
			{
				value = (*it).second;
				return true;
			}
			return false;
		}
		std::string XMLNodeTree::getAttributeValueByName(const std::string& attribName)
		{
			std::string value;
			if(!getAttributeValueByName(attribName,value))
			{
				std::stringstream ss;
				ss << "No existe un atributo con nombre " << attribName;
				THROW_EXCEPTION(lpe::core::xmlParsingException, ss.str());
				return "";
			}
			return value;
		}
		const XMLNodeTree* XMLNodeTree::searchNodeNameRecursive(const std::string& name) const
		{
			if(m_nodeName == name)
				return (const XMLNodeTree*) this;
			std::vector<XMLNodeTree*>::const_iterator it = m_childNodeList.begin();
			for(;it != m_childNodeList.end(); ++it)
			{
				const XMLNodeTree* result = (*it)->searchNodeNameRecursive(name);
				if (result != NULL)
					return result;
			}
			return NULL;
		}

		const std::map<std::string, std::string>& XMLNodeTree::getAttributeMap()
		{
			return m_nodeAttributes;
		}
		std::string XMLNodeTree::getNodeName() const
		{
		    return m_nodeName;
		}

		std::string XMLNodeTree::getNodeValueAsString() const
		{
		    return m_nodeText;
		}
		uint32_t XMLNodeTree::getNodeValueAsUnsignedInt() const
		{
			if(m_nodeText.length() == 0)
				return 0;
			return (uint32_t)atoi(getNodeValueAsString().c_str());
		}
		float XMLNodeTree::getNodeValueAsFloat() const
		{
			if(m_nodeText.length() == 0)
				return 0.0f;
			return atof(getNodeValueAsString().c_str());
		}
		int32_t XMLNodeTree::getNodeValueAsInt() const
		{
			if(m_nodeText.length() == 0)
				return 0;
			return (int32_t)atoi(getNodeValueAsString().c_str());
		}
		bool XMLNodeTree::getNodeValueAsBool() const
		{
			std::string nodeTextUpper(boost::to_upper_copy(m_nodeText));
			if(nodeTextUpper == "TRUE")
				return true;
			return false;
		}
		uint32_t XMLNodeTree::getNumberOfAttributes() const
		{
			return m_nAttributes;
		}
		uint32_t XMLNodeTree::getNumberOfChilds() const
		{
			return m_childNodeList.size();
		}
		XMLNodeTree* XMLNodeTree::getChildNodeAt(uint32_t idx)
		{
			if(idx > m_childNodeList.size())
				return NULL;
			return m_childNodeList[idx];
		}
	}
}







